/*
 * @FilePath     : /study_code/vue/principle3.js
 * @Description  : 封装类，实现 依赖跟踪
 * @Date         : 2025-04-29 17:03:00
 * @Author       : Fang YingGui
 * @LastEditors  : fangyinggui 18715384437@163.com
 * @LastEditTime : 2025-04-29 17:03:00
 */
/**
 * @brief: Dep 依赖跟踪类
 * !核心：depend, notify 方法
 * @return {*}
 */
window.Dep = class Dep {
  constructor() {
    // 订阅任务队列，方式有相同的任务（用 Set数据结构简单处理 - 去重）
    this.subscribers = new Set()
  }
  // 用于注册依赖项
  depend() {
    // #函数本质是一个对象，赋值函数，就会覆盖原先的 null 值（这里意思是只要 activeUpdate 有值，就会执行下面的代码）
    console.log('值？', activeUpdate)
    if (activeUpdate) {
      this.subscribers.add(activeUpdate)
    }
  }
  // !用于发布消息，触发依赖项重新执行 （传入的回调会再执行一次）
  notify() {
    this.subscribers.forEach(sub => sub())
  }
}

// 控制变量
let activeUpdate = null

/**
 * @brief:
 * @param {*} update 一个回调函数
 * !创建一个响应区（当代码放在这个响应区内，就可以通过 dep.depend 注册依赖项）
 * @return {*}
 */
function autorun(update) {
  const wrappedUpdate = () => {
    console.log('x', wrappedUpdate)
    activeUpdate = wrappedUpdate
    console.log('y', activeUpdate)
    // !activeUpdate 被赋予的值是当前函数
    console.log('activeUpdate被赋的值', activeUpdate)
    update()
    activeUpdate = null
  }
  wrappedUpdate()
}

// #预期结果： Dep 类期望达到的效果，调用 dep.depend 方法收集依赖，当调用 dep.notify 方法，控制台会再次输出 updated 语句

const dep = new Dep()
console.log(1, dep)
/*
1、const dep = new Dep()
构建了一个 dep 实例
constructor 构造函数在当前实例上声明了一个 subscribers 属性，是一个 空的(size为0) Set 对象
同时实例的原型上有 depend, notify 方法
*/

/*
2、执行 autorun 函数
函数内先声明 wrappedUpdate 函数，
再调用这个函数，调用中：
先给值为 null 的全局变量 activeUpdate 赋值当前函数；
再执行一句 log，控制台打印 'activeUpdate被赋的值' 变量指向 wrappedUpdate 函数
再执行参数 update，即下面调用传入的回调参数；
先执行 dep.depend()，会执行 dep 实例原型上的方法；
方法是：只要 activeUpdate 有值，就向 subscribers 对应的 Set 对象中 add 这个函数；
继续 log 'updated'，
再给变量 activeUpdate 赋 null
*/
autorun(() => {
  dep.depend()
  console.log('updated') // 这里可以理解为依赖项
}) // 打印: "updated"

dep.notify() // 打印: "updated"
/*
3、执行 dep.notify()
循环 Set 对象，参数 sub 是形参；
sub() 是调用存在 Set 中的函数，即上面 autorun 传入的函数；
执行的 sub() 内 activeUpdate 和 wrappedUpdate 都指向当前函数
是之前那个函数；
再控制台 log 'updated'，
再把 activeUpdate 置为 null，
执行结束
*/

/*
subscribers 属性中存的叫 “响应式依赖”
*/
